package userModify

import (
	"errors"
	"github.com/gin-gonic/gin"
	. "go_tempate/SQL/redis"
	. "go_tempate/SQL/table"
	. "go_tempate/common/function"
	. "go_tempate/common/store"
	customStruct "go_tempate/common/struct"
	. "go_tempate/common/validator"
	"strconv"
)

// 密码+密保验证工具函数
// ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
func PasswordAndSecurity(user *UserInfo, change *ChangePassword) error {
	//生成前端加密格式的密码
	//----------------------------------------------------------------------------------------------------------
	pePassword, err := GenerateFromPassword(change.NewPassword, false)

	//如果生成失败
	if err != nil {
		return errors.New(UserNewPasswordEncryptionErr)
	}

	//对比老密码是否正确
	//----------------------------------------------------------------------------------------------------------
	ok, err2 := ComparePasswordAndHash(change.OlderPassword, user.LoginInfo.Password)

	//如果有错误
	if err2 != nil {
		return errors.New(OldPasswordComparisonFailed)
	} else if !ok {
		return errors.New(OldPasswordComparisonError)
	}

	//对比新旧密码
	//----------------------------------------------------------------------------------------------------------
	ok, err2 = ComparePasswordAndHash(pePassword, user.LoginInfo.Password)

	//如果有错误
	if err2 != nil {
		return errors.New(FailedToCompareOldAndNewPasswords)
	} else if ok {
		return errors.New(ConsistentOldAndNewPasswords)
	}

	//用户当前设置密保合计
	//----------------------------------------------------------------------------------------------------------
	oldUserSecurity := map[uint]string{}        // 数据记录map
	removeDuplicatesSecurity := map[uint]bool{} // 去重map

	//将目前用户id作为oldUserSecurity的key，并将存储的答案传入
	for _, v := range user.UserSecurity {
		oldUserSecurity[v.SecurityTypeId] = v.Answer
	}

	//验证密保
	//----------------------------------------------------------------------------------------------------------
	for _, item := range change.VerifySecurityItem {
		//验证每个成员是否符合条件
		//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
		errs := ValidatorVerify(item)

		if errs != nil {
			return errors.New(UserConfidentialityFormatError)
		}

		//验证传入的是否存在相同的类型
		//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
		removeStatus := removeDuplicatesSecurity[item.TypeId] // 获取此时的成员是否重复

		//如果重复
		if removeStatus {
			return errors.New(UserConfidentialityRepeat)
		}

		//记录此时成员的状态
		removeDuplicatesSecurity[item.TypeId] = true

		//数据记录并验证
		//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
		oldAnswerStr := oldUserSecurity[item.TypeId] // 获取此时 oldUserSecurity 的记录值

		//如果此时传入的id在 oldUserSecurity 中并没有记录，则表示此问题并不是此用户设置
		if oldAnswerStr == "" {
			return errors.New(UserHaveNotConfidentiality)
		}

		//进行比对库中的加密密保问题和传入的老密保问题是否一致
		//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
		ok, err := ComparePasswordAndHash(item.Answer, oldAnswerStr)

		//如果验证报错或验证失败
		if err != nil {
			return errors.New(UserConfidentialityTestError)
		} else if !ok {
			return errors.New(SecurityComparisonError)
		}
	}

	//全部验证通过后对新密码进行加密然后返回成功
	//----------------------------------------------------------------------------------------------------------
	change.NewPassword, err = GenerateFromPassword(pePassword, true)

	//如果加密失败
	if err != nil {
		return errors.New(UserNewPasswordEncryptionErr)
	}

	//进行入库操作
	//----------------------------------------------------------------------------------------------------------
	err = user.LoginInfo.SetLoginInfoPassword(change.NewPassword)

	//如果入库失败
	if err != nil {
		return errors.New(NewPasswordWarehousingFailed)
	}

	//全部通过则返回没有错误并清空当前用户的token记录
	//----------------------------------------------------------------------------------------------------------
	err = DeleteRedisItem(strconv.Itoa(int(user.ID)))

	if err != nil {
		return errors.New(DeleteTokenInRedisError)
	}

	return nil
}

// 删除+冻结+解冻接口工具函数
// ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
func DelOrFreezeOrThaw(ctx *gin.Context, body *customStruct.ResponseBody) *UserInfo {

	//首先获取传入的userId参数
	//----------------------------------------------------------------------------------------------------------
	userIdStr := ctx.Query("userId")

	//如果并未有此数据则抛出错误
	if userIdStr == "" {
		body.BatchSettings(GetRequestContentErr, UserIdCannotBeEmpty, nil)
		return nil
	}

	//声明用户信息表，转化获取到的userId,并查询对应的用户是否存在
	//----------------------------------------------------------------------------------------------------------
	userInfo := UserInfo{}
	userId, _ := strconv.ParseUint(userIdStr, 10, 64)
	err := userInfo.OnceUser(uint(userId))

	//发生查询错误时
	if err != nil {
		body.BatchSettings(GetUserInfoErr, GetUserIdError, nil)
		return nil

	} else if userInfo.Name == "" {
		//如果并未查询到用户信息
		body.BatchSettings(NotUserInfo, NotUserInfoMessage, nil)
		return nil
	}

	return &userInfo
}
